package com.bwie.patient.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bwie.common.domain.request.MessageVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;



@Component
@Slf4j
@ServerEndpoint("/websocket/{room}/{name}")
public class WebSocketServer {
    /**
     * 静态变量，用来记录当前在线连接数，线程安全的类。
     */
    private static final AtomicInteger onlineSessionClientCount = new AtomicInteger(0);

    /**
     * 存放所有在线的客户端
     */
    private static final Map<String, Map<String, Session>> onlineSessionClientMap = new ConcurrentHashMap<>();

    /**
     * 连接 room、name 和连接会话
     */
    private String room;
    private String name;

    @OnOpen
    public void onOpen(@PathParam("room") String room, @PathParam("name") String name, Session session) {
        this.room = room;
        this.name = name;

        // 获取该房间的客户端会话Map
        Map<String, Session> roomClients = onlineSessionClientMap.getOrDefault(room, new ConcurrentHashMap<>());

        // 如果该房间不存在，则创建新的房间
        if (roomClients.isEmpty()) {
            onlineSessionClientMap.put(room, roomClients);
        }

        // 检查是否有同名用户已经连接在该房间中
        if (roomClients.containsKey(name)) {
            // 在线数减1
            onlineSessionClientCount.decrementAndGet();
            log.info("连接已存在，关闭之前的连接 ==> room = {}， name = {}。", room, name);

            // 通知之前的连接被挤掉
            sendToOne(room, name, "您的账号在其他地方登录，您被迫下线。");

            // 从 Map 中移除
            roomClients.remove(name);
        }

        // 将新连接加入房间中
        roomClients.put(name, session);

        // 在线数加1
        onlineSessionClientCount.incrementAndGet();

        sendToOne(room, name, "连接成功");

        log.info("连接建立成功，当前在线数为：{} ==> 开始监听新连接：room = {}， name = {}。", onlineSessionClientCount, room, name);
    }


    @OnClose
    public void onClose(@PathParam("room") String room, @PathParam("name") String name, Session session) {
        // 获取该房间的客户端会话Map
        Map<String, Session> roomClients = onlineSessionClientMap.get(room);

        if (roomClients != null) {
            // 从 Map 中移除
            roomClients.remove(name);

            // 在线数减1
            onlineSessionClientCount.decrementAndGet();
            log.info("连接关闭成功，当前在线数为：{} ==> 关闭该连接信息：room = {}， name = {}。", onlineSessionClientCount, room, name);
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        JSONObject jsonObject = JSON.parseObject(message);
        String toname = jsonObject.getString("name");
        String msg = jsonObject.getString("message");

        log.info("服务端收到客户端消息 ==> fromname = {}, toname = {}, message = {}", name, toname, message);

        /**
         * 模拟约定：如果未指定toname信息，则群发给房间内的所有人，否则就单独发送给指定人
         */
        if (toname == null || toname.isEmpty()) {
            sendToRoom(room, name, msg);
        } else {
            sendToOne(room, toname, msg);
        }
    }

    /**
     * 发送消息给房间内的所有人
     *
     * @param room    房间名
     * @param from    发送者名字
     * @param message 消息内容
     */
    private void sendToRoom(String room, String from, String message) {
        // 获取该房间的客户端会话Map
        Map<String, Session> roomClients = onlineSessionClientMap.get(room);

        if (roomClients != null) {
            // 遍历房间内所有客户端会话
            roomClients.forEach((name, toSession) -> {
                // 排除掉发送者自己
                if (!name.equalsIgnoreCase(from)) {
                    log.info("服务端给客户端群发消息 ==> room = {}, fromname = {}, toname = {}, message = {}", room, from, name, message);

                    MessageVo messageVo = new MessageVo();
                    messageVo.setFrom(from);
                    messageVo.setDate(new Date());
                    messageVo.setMessage(message);

                    toSession.getAsyncRemote().sendText(JSON.toJSONString(messageVo));
                }
            });
        }
    }

    /**
     * 发送消息给指定房间内的指定人
     *
     * @param room    房间名
     * @param toName  接收者名字
     * @param message 消息内容
     */
    private void sendToOne(String room, String toName, String message) {
        // 获取该房间的客户端会话Map
        Map<String, Session> roomClients = onlineSessionClientMap.get(room);

        if (roomClients != null) {
            // 通过toName查询对应的客户端会话
            Session toSession = roomClients.get(toName);

            if (toSession != null) {
                log.info("服务端给客户端发送消息 ==> room = {}, fromname = {}, toname = {}, message = {}", room, name, toName, message);

                MessageVo messageVo = new MessageVo();
                messageVo.setFrom(name);
                messageVo.setDate(new Date());
                messageVo.setMessage(message);

                toSession.getAsyncRemote().sendText(JSON.toJSONString(messageVo));
            } else {
                log.error("服务端给客户端发送消息 ==> room = {}, toname = {} 不存在, message = {}", room, toName, message);
            }
        }
    }
}
